package me.yushuai.wukong.base.service.impl;

import me.yushuai.wukong.base.api.dto.CreateZoneDTO;
import me.yushuai.wukong.base.api.dto.PagingSearchZone;
import me.yushuai.wukong.base.api.dto.UpdateZoneDTO;
import me.yushuai.wukong.base.api.dto.ZoneDTO;
import me.yushuai.wukong.base.convertor.ZoneConvertor;
import me.yushuai.wukong.base.entity.Zone;
import me.yushuai.wukong.base.entity.ZoneGroup;
import me.yushuai.wukong.base.repository.ZoneRepository;
import me.yushuai.wukong.base.service.ZoneGroupService;
import me.yushuai.wukong.base.service.ZoneService;
import me.yushuai.wukong.common.dto.PageDTO;
import me.yushuai.wukong.common.exceptin.BizIdNotExistException;
import me.yushuai.wukong.common.exceptin.DuplicateBizIdException;
import me.yushuai.wukong.common.exceptin.NotExistException;
import me.yushuai.wukong.common.service.impl.AbstractPageableService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 库区业务实现类，库区的业务类使用乐观锁解决并发问题
 *
 * @author zhoushuai@189.cn
 * @since 2022-08-25
 */
@Service
public class ZoneServiceImpl extends AbstractPageableService<ZoneDTO, Zone> implements ZoneService {

    /**
     * 库区编号不存
     */
    public static final String ZONE_ID_NOT_FOUND = "zone.zoneId.notFound";

    /**
     *
     */
    public static final String ZONE_CODE_NOT_FOUND = "zone.zoneCode.notFound";

    /**
     * 库区编码已存在
     */
    public static final String ZONE_CODE_HAS_EXIST = "zone.zoneCode.hasExist";

    /**
     *
     */
    public static final String ZONE_ID_AND_ZONE_CODE_NOT_MATCH = "zone.zoneIdAndZoneCode.notMatch";

    @Autowired
    private ZoneConvertor zoneConvertor;

    private final ZoneRepository zoneRepository;

    /**
     * 仓库区域业务类
     */
    @Autowired
    private ZoneGroupService zoneGroupService;

    @Autowired
    public ZoneServiceImpl(ZoneRepository zoneRepository) {
        super(zoneRepository);
        this.zoneRepository = zoneRepository;
    }


    @Override
    public Long createZone(CreateZoneDTO dto) throws NotExistException, DuplicateBizIdException {
        //1. 检查库区编码是否存在
        final String bizId = dto.getBizId();
        if (this.existsByBizId(bizId)) {
            throw new DuplicateBizIdException(bizId, Zone.class);
        }

        //2. 检索库区所属区域是否存在
        final Long zoneGroupId = dto.getZoneGroupId();
        if (Objects.nonNull(zoneGroupId) && !this.zoneGroupService.existsById(zoneGroupId)) {
            throw new NotExistException(zoneGroupId, "Zone.zoneGroupId");
        }

        //3. 新增库区
        final Zone zone = this.zoneConvertor.mapToEntity(dto);
        this.zoneRepository.save(zone);
        return zone.getZoneId();
    }


    @Override
    public Long updateZone(UpdateZoneDTO dto) throws NotExistException {

        //1. 检查库区编码与库区编码是否匹配
        final String bizId = dto.getBizId();
        if (!this.zoneRepository.existsByBizId(bizId)) {
            throw new NotExistException(bizId, Zone.class);
        }

        //2. 检查仓库区域是否合法
        final Long zoneGroupId = dto.getZoneGroupId();
        if (!this.zoneGroupService.existsById(zoneGroupId)) {
            throw new NotExistException(zoneGroupId, ZoneGroup.class);
        }

        //3. 准备更新库区的信息
        final Zone zone = this.zoneConvertor.mapToEntity(dto);
        this.zoneRepository.save(zone);

        return dto.getZoneId();
    }

    @Override
    public void deleteZone(Long zoneId) throws NotExistException {
        //1. 检查库区是否存在
        if (!this.existsById(zoneId)) {
            throw new NotExistException(zoneId, Zone.class);
        }

        //2. 删除库区记录
        this.zoneRepository.deleteById(zoneId);
    }

    @Override
    public ZoneDTO findZoneById(Long zoneId) throws NotExistException {
        //1. 通过zoneId查询库区信息
        final Zone zone = getZoneOrThrow(zoneId);

        //3. 返回查询结果
        return this.zoneConvertor.mapToDto(zone);
    }


    @Override
    public ZoneDTO findZoneByBizId(String bizId) throws BizIdNotExistException {
        //1. 通过zoneId查询库区信息
        final Zone zone = getZoneOrThrow(bizId);

        //3. 返回查询结果
        return this.zoneConvertor.mapToDto(zone);
    }


    @Override
    public PageDTO<ZoneDTO> pagingSearch(@NotNull PagingSearchZone pagingSearchZone) {

        // 1. 查询条件
        final Specification<Zone> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            final String zoneCode = pagingSearchZone.getZoneCode();

            if (StringUtils.hasText(zoneCode)) {
                list.add(criteriaBuilder.equal(root.get("zoneCode").as(String.class), zoneCode));
            }

            return criteriaBuilder.and(list.toArray(Predicate[]::new));
        };

        //3. 执行查询并返回结果
        return super.pagingSearch(pagingSearchZone, spec, this.zoneConvertor::mapToDtoList);
    }

    @Override
    public boolean existsById(Long zoneId) {
        return this.zoneRepository.existsById(zoneId);
    }

    @Override
    public boolean existsByBizId(String bizId) {
        return this.zoneRepository.existsByBizId(bizId);
    }

    // -------------------------------------------private method-------------------------------------------

    private Zone getZoneOrThrow(Long zoneId) throws NotExistException {
        return this.zoneRepository.findById(zoneId)
                .orElseThrow(() -> new NotExistException(zoneId, Zone.class));
    }

    private Zone getZoneOrThrow(String bizId) throws BizIdNotExistException {
        return this.zoneRepository.findByBizId(bizId)
                .orElseThrow(() -> new BizIdNotExistException(bizId, Zone.class));
    }
}




